Skip to content

🩹 Self-Healing Agents

Self-healing is the capacity of an autonomous agent to detect execution failures (such as linter warnings, syntax crashes, or test suite errors), capture the diagnostics, feed the feedback logs back into its own context, and execute recursive patches to correct the codebase automatically.

For related implementation concepts, see:


🔁 The Diagnostic Feedback Loop

The core mechanic of self-healing is piping compiler and linter outputs directly into LLM prompts as debugging context. This cycle continues recursively until verification succeeds or safety limits are met:


🔍 1. Syntax Checkers & Static Analysis Integration

Before running code, agents execute static analysis or compile-time checks to catch formatting, typing, and syntax errors without spinning up full test runtimes.

  • Python AST Compiling: Using Python's built-in ast module to perform compile-time verification before execution.
    python
    import ast
    
    def verify_syntax(code_string: str) -> bool:
        try:
            ast.parse(code_string)
            return True
        except SyntaxError as e:
            # Captures line number, offset, and exact syntax issue
            return False
  • Linting Engines: Running automated linter CLI commands and capturing their execution status returns.
    • Ruff (Python): ruff check path/to/file.py
    • ESLint (JavaScript/TypeScript): eslint path/to/file.js
  • Execution Status Returns: Self-healing agents inspect the shell exit status code (subprocess.CompletedProcess.returncode). Any non-zero return code (typically 1) halts standard execution and routes the process to the diagnostic handler.

📝 2. Prompt Feedback & Context Wrapping

When an error is intercepted, raw, unstructured logs are wrapped in clean Markdown templates or XML schemas to clearly separate source code, tracebacks, and instructions.

  • XML Tag Separation: Wrapping logs in tags helps LLMs isolate the error metadata from instruction prompts.
    xml
    <target_file>src/utils/jwt.py</target_file>
    
    <compiler_error>
    File "src/utils/jwt.py", line 12, in encode_token
        payload["exp"] = datetime.utcnow() + expires_delta
    NameError: name 'datetime' is not defined
    </compiler_error>
    
    <instructions>
    The code you generated failed with a NameError. Analyze the trace, identify the missing import, and write a corrected version of the file.
    </instructions>
  • Markdown Formatting Templates: Formatting logs clearly using code blocks labeled with standard syntax tags (text, python, json, bash).

🗜️ 3. Compaction & Token Conservation Strategies

Raw log outputs from test suites like pytest or build tools can span thousands of lines, quickly overwhelming the agent's context window. Effective self-healing requires summarizing and filtering these logs.

  • Traceback Filtering: Filter out system libraries (e.g., Python site-packages or Node node_modules) to only keep traces referencing local workspace paths.
  • Error Compaction Scripting: Parse stderr outputs using regular expressions to extract only the core problem statement:
    python
    import re
    
    def compact_traceback(raw_stderr: str) -> str:
        # Extract filename, line number, and error messages
        matches = re.findall(r'File "([^"]+)", line (\d+), in (.*)\n(.*)\n([^:]+): (.*)', raw_stderr)
        if not matches:
            return raw_stderr[:500]  # Fallback to truncated raw logs
        
        compacted = []
        for file, line, func, context, err_type, err_msg in matches:
            compacted.append(f"File: {file} (Line {line}) in {func}\n  Code: {context.strip()}\n  Error: {err_type}: {err_msg}")
        return "\n\n".join(compacted)

🛡️ 4. Iteration Bounds & Infinite Loop Prevention

Self-healing is inherently recursive. Without constraints, an agent might oscillate between conflicting fixes (e.g., fixing type checking but breaking syntax, then reversing the fix).

  • Iteration Guard Parameters: Always enforce a strict loop boundary counter (e.g., MAX_ATTEMPTS = 3).
  • Oscillation Detection: Track generated file hashes. If the agent generates an identical file version to one from two iterations ago, break the loop early.
  • Graceful Degradation: If loop counts are exceeded, transition automatically to:
    1. Human-in-the-Loop Prompting: Stop autonomous execution and alert the developer, providing the compilation history and trace details.
    2. State Rollback: Revert changes using local Git checkouts to return the workspace to a compiling state.